package com.example.backend.service;

import com.example.backend.annotation.LogExecution;
import com.example.backend.domain.entity.User;
import com.example.backend.domain.enums.Role;
import com.example.backend.domain.enums.UserStatus;
import com.example.backend.dto.CreateUserRequest;
import com.example.backend.dto.UpdateUserRequest;
import com.example.backend.dto.UserFilter;
import com.example.backend.exception.BusinessException;
import com.example.backend.repository.UserRepository;
import com.example.backend.repository.spec.UserSpecifications;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.List;
import java.util.Optional;

@Service
@Transactional
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @LogExecution("保存用户")
    @CacheEvict(value = "users", allEntries = true)
    public User save(User user) {
        return userRepository.save(user);
    }

    @LogExecution("更新用户")
    @CacheEvict(value = "users", allEntries = true)
    public User update(User user) {
        return userRepository.save(user);
    }

    @LogExecution("根据ID查找用户")
    @Cacheable(value = "users", key = "#id", unless = "#result == null")
    @Transactional(readOnly = true)
    public Optional<User> findById(Long id) {
        return userRepository.findById(id);
    }

    @LogExecution("根据用户名查找用户")
    @Cacheable(value = "users", key = "'username_' + #username", unless = "#result == null")
    @Transactional(readOnly = true)
    public Optional<User> findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    @LogExecution("根据邮箱查找用户")
    @Cacheable(value = "users", key = "'email_' + #email", unless = "#result == null")
    @Transactional(readOnly = true)
    public Optional<User> findByEmail(String email) {
        return userRepository.findByEmail(email);
    }

    @LogExecution("获取所有用户")
    @Transactional(readOnly = true)
    public List<User> findAll() {
        return userRepository.findAll();
    }

    @LogExecution("检查用户名是否存在")
    @Transactional(readOnly = true)
    public boolean existsByUsername(String username) {
        return userRepository.existsByUsername(username);
    }

    @LogExecution("检查邮箱是否存在")
    @Transactional(readOnly = true)
    public boolean existsByEmail(String email) {
        return userRepository.existsByEmail(email);
    }

    // 新增的用户管理方法

    @LogExecution("创建用户")
    @CacheEvict(value = "users", allEntries = true)
    public User createUser(CreateUserRequest request) {
        // 验证密码确认
        if (!request.getPassword().equals(request.getConfirmPassword())) {
            throw new BusinessException("两次输入的密码不一致");
        }
        
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new BusinessException("用户名已存在");
        }
        
        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new BusinessException("邮箱已被注册");
        }
        
        // 验证角色
        Role role;
        try {
            role = Role.valueOf(request.getRole().toUpperCase());
        } catch (IllegalArgumentException e) {
            throw new BusinessException("无效的用户角色: " + request.getRole());
        }
        
        // 验证状态（如果提供的是字符串，转换为枚举）
        UserStatus status = UserStatus.ACTIVE;
        if (request.getStatus() != null && !request.getStatus().trim().isEmpty()) {
            try {
                status = UserStatus.valueOf(request.getStatus().toUpperCase());
            } catch (IllegalArgumentException e) {
                throw new BusinessException("无效的用户状态: " + request.getStatus());
            }
        }
        
        // 创建新用户
        User user = User.builder()
                .username(request.getUsername())
                .password(passwordEncoder.encode(request.getPassword()))
                .fullName(request.getFullName())
                .email(request.getEmail())
                .phone(request.getPhone())
                .avatarUrl(request.getAvatarUrl())
                .department(request.getDepartment())
                .position(request.getPosition())
                .employeeId(request.getEmployeeId())
                .role(role)
                .status(status)
                .loginCount(0)
                .build();
        
        return userRepository.save(user);
    }

    @LogExecution("更新用户信息")
    @CacheEvict(value = "users", allEntries = true)
    public User updateUser(Long userId, UpdateUserRequest request) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        // 检查用户名是否被其他用户使用
        if (request.getUsername() != null && !request.getUsername().equals(user.getUsername())) {
            if (userRepository.existsByUsername(request.getUsername())) {
                throw new BusinessException("用户名已被其他用户使用");
            }
            user.setUsername(request.getUsername());
        }
        
        // 检查邮箱是否被其他用户使用
        if (request.getEmail() != null && !request.getEmail().equals(user.getEmail())) {
            if (userRepository.existsByEmail(request.getEmail())) {
                throw new BusinessException("邮箱已被其他用户使用");
            }
            user.setEmail(request.getEmail());
        }
        
        // 更新其他字段
        if (request.getFullName() != null) user.setFullName(request.getFullName());
        if (request.getPhone() != null) user.setPhone(request.getPhone());
        if (request.getAvatarUrl() != null) user.setAvatarUrl(request.getAvatarUrl());
        if (request.getDepartment() != null) user.setDepartment(request.getDepartment());
        if (request.getPosition() != null) user.setPosition(request.getPosition());
        if (request.getEmployeeId() != null) user.setEmployeeId(request.getEmployeeId());
        if (request.getRole() != null) user.setRole(request.getRole());
        if (request.getStatus() != null) user.setStatus(request.getStatus());
        
        return userRepository.save(user);
    }

    @LogExecution("删除用户")
    @CacheEvict(value = "users", allEntries = true)
    @Transactional
    public void deleteUser(Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        // 防止删除管理员账户
        if (user.getRole() == Role.ADMIN) {
            throw new BusinessException("不能删除管理员账户");
        }
        
        // 使用软删除：设置状态为DELETED，而不是物理删除
        // 这样可以保留历史数据，避免外键约束问题
        user.setStatus(UserStatus.DELETED);
        userRepository.save(user);
    }

    @LogExecution("更新用户状态")
    @CacheEvict(value = "users", allEntries = true)
    public User updateUserStatus(Long userId, UserStatus status) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        user.setStatus(status);
        return userRepository.save(user);
    }

    @LogExecution("重置用户密码")
    @CacheEvict(value = "users", allEntries = true)
    public User resetUserPassword(Long userId, String newPassword) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        user.setPassword(passwordEncoder.encode(newPassword));
        return userRepository.save(user);
    }

    // 查询方法

    @LogExecution("分页获取用户列表")
    @Cacheable(value = "users_list", key = "#pageable.pageNumber + '_' + #pageable.pageSize")
    @Transactional(readOnly = true)
    public Page<User> findAll(Pageable pageable) {
        // 默认过滤已删除的用户
        Specification<User> spec = UserSpecifications.isNotDeleted();
        return userRepository.findAll(spec, pageable);
    }

    @LogExecution("按条件过滤用户列表")
    @Cacheable(value = "users_list", key = "#filter.hashCode() + '_' + #pageable.pageNumber + '_' + #pageable.pageSize")
    @Transactional(readOnly = true)
    public Page<User> findAll(UserFilter filter, Pageable pageable) {
        Specification<User> spec = UserSpecifications.withFilter(filter);
        return userRepository.findAll(spec, pageable);
    }

    @LogExecution("搜索用户")
    @Cacheable(value = "users_search", key = "#keyword + '_' + #role + '_' + #status + '_' + #pageable.pageNumber + '_' + #pageable.pageSize")
    @Transactional(readOnly = true)
    public Page<User> searchUsers(String keyword, Role role, UserStatus status, String department, Pageable pageable) {
        return userRepository.searchUsers(keyword, role, status, department, pageable);
    }

    @LogExecution("根据角色获取用户")
    @Cacheable(value = "users", key = "'role_' + #role + '_' + #pageable.pageNumber + '_' + #pageable.pageSize")
    @Transactional(readOnly = true)
    public Page<User> findByRole(Role role, Pageable pageable) {
        return userRepository.findByRole(role, pageable);
    }

    @LogExecution("根据状态获取用户")
    @Cacheable(value = "users", key = "'status_' + #status + '_' + #pageable.pageNumber + '_' + #pageable.pageSize")
    @Transactional(readOnly = true)
    public Page<User> findByStatus(UserStatus status, Pageable pageable) {
        return userRepository.findByStatus(status, pageable);
    }

    @LogExecution("根据部门获取用户")
    @Cacheable(value = "users", key = "'department_' + #department + '_' + #pageable.pageNumber + '_' + #pageable.pageSize")
    @Transactional(readOnly = true)
    public Page<User> findByDepartment(String department, Pageable pageable) {
        return userRepository.findByDepartment(department, pageable);
    }

    // 统计方法

    @LogExecution("获取用户统计信息")
    @Cacheable(value = "users_stats", key = "'distribution'")
    @Transactional(readOnly = true)
    public UserStatistics getUserStatistics() {
        List<Object[]> roleDistribution = userRepository.getRoleDistribution();
        List<Object[]> departmentStats = userRepository.getDepartmentStats();
        long totalUsers = userRepository.count();
        long activeUsers = userRepository.countByStatus(UserStatus.ACTIVE);
        
        return new UserStatistics(roleDistribution, departmentStats, totalUsers, activeUsers);
    }

    @LogExecution("获取用户趋势分析")
    @Cacheable(value = "users_stats", key = "'trend_' + #startDate + '_' + #endDate")
    @Transactional(readOnly = true)
    public List<Object[]> getUserTrendAnalysis(Instant startDate, Instant endDate) {
        return userRepository.getUserTrendData(startDate, endDate);
    }

    @LogExecution("获取活跃用户")
    @Cacheable(value = "users", key = "'active_' + #since")
    @Transactional(readOnly = true)
    public List<User> getActiveUsers(Instant since) {
        return userRepository.findActiveUsers(since);
    }

    @LogExecution("获取最新用户")
    @Cacheable(value = "users", key = "'latest'")
    @Transactional(readOnly = true)
    public List<User> getLatestUsers() {
        return userRepository.findTop5ByOrderByCreatedAtDesc();
    }

    // 内部统计类
    public static class UserStatistics {
        private final List<Object[]> roleDistribution;
        private final List<Object[]> departmentStats;
        private final long totalUsers;
        private final long activeUsers;

        public UserStatistics(List<Object[]> roleDistribution, List<Object[]> departmentStats, long totalUsers, long activeUsers) {
            this.roleDistribution = roleDistribution;
            this.departmentStats = departmentStats;
            this.totalUsers = totalUsers;
            this.activeUsers = activeUsers;
        }

        // Getters
        public List<Object[]> getRoleDistribution() { return roleDistribution; }
        public List<Object[]> getDepartmentStats() { return departmentStats; }
        public long getTotalUsers() { return totalUsers; }
        public long getActiveUsers() { return activeUsers; }
    }
}


